﻿#pragma once

#include <Windows.h>
#include <stdio.h>
#include <iostream> 
#include <fstream>
#include "..\..\include\common\MD5\md5.h"
#include "..\..\include\common\NET_CMD.h"
 
#pragma comment(lib, "Ws2_32.lib")

using namespace std;

#define DEFAULT_SERVER "127.0.0.1"
#define DEFAULT_PORT 9527

//////////////////////////////////////////////////////////////////////////
//函数声明

bool QueryVersion(char *lpRet);
BOOL InitWinsock();
bool Login(char *lpUsername, char *lpPassword, char *lpMachineCode);
void SynHeart();
bool Recharge(char *lpCardId, char *lpCardPassword, char *lpRechargeUser, char *lpMachineCode);
bool RegisterUser(char *lpUsername, char *lpPassword, char *lpQQNumber);

SOCKET sckLogin;
//////////////////////////////////////////////////////////////////////////
int main()
{
	InitWinsock();

__Start:
	system("cls");
	printf("1.发送本地版本号\n");
	printf("2.发送登录请求\n");
	printf("3.发送心跳包\n");
	printf("  (密码需要MD5(MD5())加密。)\n");
	printf("4.发送充值请求\n");
	printf("5.发送注册请求\n");
	printf("\n\n");

	printf("请输入要发送的指令：");
	char szCmd[1] = {0};

	while (cin >> szCmd)
	{
		printf("--------------------------------------------\n");

		//查询版本号
		if (szCmd[0] == '1')
		{
			
			char *lpRet = new char[128];
			if (QueryVersion(lpRet) == false)
			{
				MessageBoxA(0, lpRet, "登录失败", MB_ICONWARNING);
			}
		}
		//登录请求
		else if (szCmd[0] == '2')
		{
			Login("powman", "123456", "MachineCode");
		}
		//心跳包请求
		else if (szCmd[0] == '3')
		{
			
			SynHeart();
		}
		//充值请求
		else if (szCmd[0] == '4')
		{
			Recharge("AAAABBBB", "123456", "powman", "MachineCode");
		}
		//用户注册请求
		else if (szCmd[0] == '5')
		{
			RegisterUser("powmanx", "123456", "138001655");
		}

		printf(" - 按任意键输入新的指令...\n");
		system("pause");
		goto __Start;
	}

	getchar();
	return 0;

}

//////////////////////////////////////////////////////////////////////////
//功能函数
//////////////////////////////////////////////////////////////////////////

//初始化Winsock库
BOOL InitWinsock()
{
	//构造一个WSADATA结构的指针
	WSADATA wsaData;

	//调用WSAStartup()初始化Winsock库，这里我们统一使用Winsock2的子版本，2.2版。用MAKEWORD宏来构造版本号。
	int nResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
	if (nResult != 0)
	{
		//调用错误的情况
		::OutputDebugStringA("初始化Winsock库失败！\n");
		WSACleanup();
		return FALSE;
	}

	//判断加载的版本号是否正常
	if (HIBYTE(wsaData.wVersion) != 2 || LOBYTE(wsaData.wVersion) != 2)
	{
		::OutputDebugStringA("初始化Winsock库失败，版本号异常！\n");
		WSACleanup();
		return FALSE;
	}

	return TRUE;
}

//请求版本号
bool QueryVersion(char *lpRet)
{
	ifstream infile;
	infile.close();
	infile.clear();

	char lpVersion[MAX_VERSION_LEN] = {0};

	infile.open("version.dat", ifstream::in);
	if(!infile)
	{
		sprintf_s(lpVersion, MAX_VERSION_LEN, "0");
	}

	infile.read(lpVersion, MAX_VERSION_LEN);
	printf("读取到的本地版本号：%s\n", lpVersion);
	infile.close();

	printf("正在发送本地版本号...\n");

	//创建套接字
	SOCKET sckQueryVersion = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

	//设置地址族信息并连接到服务器
	sockaddr_in addr;
	addr.sin_addr.S_un.S_addr = inet_addr(DEFAULT_SERVER);
	addr.sin_family = AF_INET;
	addr.sin_port = htons(DEFAULT_PORT);

	::connect(sckQueryVersion, (const sockaddr*)&addr, sizeof(addr));

	NET_CMD cmd;
	cmd.nCmd = CMD_QUERY_VERSION;
	strncpy_s(cmd.szVersion, lpVersion, MAX_VERSION_LEN);
	::send(sckQueryVersion, (char*)&cmd, sizeof(cmd), 0);

	NET_CMD cmdRecv;
	::recv(sckQueryVersion, (char*)&cmdRecv, sizeof(cmdRecv), 0);
	if (cmdRecv.nCmd = CMD_QUERY_VERSION && cmdRecv.bAllow == true)
	{
		printf("版本号验证通过，服务端允许登录！\n");
	}
	else if (cmdRecv.nCmd = CMD_QUERY_VERSION && cmdRecv.bAllow == false)
	{
		printf("%s\n", cmdRecv.szWarningText);
	}
	closesocket(sckQueryVersion);
	 
	return true;
}

//发送登录请求
bool Login(char *lpUsername, char *lpPassword, char *lpMachineCode)
{
	//创建套接字
	sckLogin = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

	//设置地址族信息并连接到服务器
	sockaddr_in addr;
	addr.sin_addr.S_un.S_addr = inet_addr(DEFAULT_SERVER);
	addr.sin_family = AF_INET;
	addr.sin_port = htons(DEFAULT_PORT);

	::connect(sckLogin, (const sockaddr*)&addr, sizeof(addr));

	NET_CMD cmd;
	cmd.nCmd = CMD_LOGIN;
	strncpy_s(cmd.szUsername, lpUsername, MAX_USERNAME_LEN);

	//是否需要验证机器码
	if (VERIFY_MACHINE_CODE == true)
	{
		strncpy_s(cmd.szMachineCode, lpMachineCode, MAX_MACHINECODE_LEN);
	}

	//密码进行两次MD5
	string strPassword(lpPassword);
	MD5 md5_1(strPassword);
	MD5 md5_2(md5_1.toString().c_str());
	strPassword = md5_2.toString();

	printf("密码进行两次MD5后的结果：%s\n", md5_2.toString().c_str());
	strncpy(cmd.szPassword, strPassword.c_str(), MAX_PASSWORD_LEN);
	::send(sckLogin, (char*)&cmd, sizeof(cmd), 0);

	NET_CMD cmdRecv;
	::recv(sckLogin, (char*)&cmdRecv, sizeof(cmdRecv), 0);
	if (cmdRecv.nCmd = CMD_LOGIN && cmdRecv.bAllow == true)
	{
		printf("登录成功，客户端密钥：%s\n", cmdRecv.szClientKey);
	}
	else if (cmdRecv.nCmd = CMD_LOGIN && cmdRecv.bAllow == false)
	{
		printf("%s\n", cmdRecv.szWarningText);
	}

	return true;
}

//心跳包
void SynHeart()
{
	NET_CMD cmd;
	cmd.nCmd = CMD_C_HEART_PACKET;
	::send(sckLogin, (char*)&cmd, sizeof(cmd), 0);
}

//发送注册请求
bool RegisterUser(char *lpUsername, char *lpPassword, char *lpQQNumber)
{

	//创建套接字
	SOCKET sckRegister = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

	//设置地址族信息并连接到服务器
	sockaddr_in addr;
	addr.sin_addr.S_un.S_addr = inet_addr(DEFAULT_SERVER);
	addr.sin_family = AF_INET;
	addr.sin_port = htons(DEFAULT_PORT);

	::connect(sckRegister, (const sockaddr*)&addr, sizeof(addr));

	NET_CMD cmd;
	cmd.nCmd = CMD_REGISTER;

	//密码进行两次MD5
	string strPassword(lpPassword);
	MD5 md5_1(strPassword);
	MD5 md5_2(md5_1.toString().c_str());
	strPassword = md5_2.toString();

	strncpy(cmd.szUsername, lpUsername, MAX_USERNAME_LEN);
	strncpy(cmd.szPassword, strPassword.c_str(), MAX_PASSWORD_LEN);
	strncpy(cmd.szQQNumber, lpQQNumber, MAX_QQNUMBER_LEN);
	::send(sckRegister, (char*)&cmd, sizeof(cmd), 0);

	NET_CMD cmdRecv;
	::recv(sckRegister, (char*)&cmdRecv, sizeof(cmdRecv), 0);
	if (cmdRecv.nCmd = CMD_REGISTER && cmdRecv.bAllow == true)
	{
		printf("注册成功！\n");
	}
	else if (cmdRecv.nCmd = CMD_REGISTER && cmdRecv.bAllow == false)
	{
		printf("%s\n", cmdRecv.szWarningText);
	}
	closesocket(sckRegister);

	return true;
}

//充值请求
bool Recharge(char *lpCardId, char *lpCardPassword, char *lpRechargeUser, char *lpMachineCode)
{
	//创建套接字
	SOCKET sckRecharge = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

	//设置地址族信息并连接到服务器
	sockaddr_in addr;
	addr.sin_addr.S_un.S_addr = inet_addr(DEFAULT_SERVER);
	addr.sin_family = AF_INET;
	addr.sin_port = htons(DEFAULT_PORT);

	::connect(sckRecharge, (const sockaddr*)&addr, sizeof(addr));

	NET_CMD cmd;
	cmd.nCmd = CMD_RECHARGE;
	strncpy_s(cmd.szCardId, lpCardId, CARD_ID_LEN);
	strncpy_s(cmd.szCardPass, lpCardPassword, CARD_PASS_LEN);
	strncpy_s(cmd.szUsername, lpRechargeUser, MAX_USERNAME_LEN);
	
	//是否需要验证机器码
	if (VERIFY_MACHINE_CODE == true)
	{
		strncpy_s(cmd.szMachineCode, lpMachineCode, MAX_MACHINECODE_LEN);
	}

	printf("正在充值...\n");
	::send(sckRecharge, (char*)&cmd, sizeof(cmd), 0);

	NET_CMD cmdRecv;
	::recv(sckRecharge, (char*)&cmdRecv, sizeof(cmdRecv), 0);
	printf("正在判断结果...\n");
	if (cmdRecv.nCmd = CMD_RECHARGE && cmdRecv.bAllow == true)
	{
		printf("充值成功！\n", cmdRecv.szClientKey);
	}
	else if (cmdRecv.nCmd = CMD_RECHARGE && cmdRecv.bAllow == false)
	{
		printf("%s\n", cmdRecv.szWarningText);
	}
	closesocket(sckRecharge);
	return true;
}